Skip to content

[STORE] abstract snapshot catalog and add Redis snapshot backend - #1739

Merged
XucSh merged 6 commits into
kvcache-ai:mainfrom
openanolis:xinyi/ha-snapshot
Mar 27, 2026
Merged

[STORE] abstract snapshot catalog and add Redis snapshot backend#1739
XucSh merged 6 commits into
kvcache-ai:mainfrom
openanolis:xinyi/ha-snapshot

Conversation

@YiXR

@YiXR YiXR commented Mar 25, 2026

Copy link
Copy Markdown
Collaborator

Description

This PR abstracts snapshot catalog handling in mooncake-store and adds a Redis-backed snapshot catalog implementation.

Today, snapshot catalog logic is embedded in MasterService, which makes it hard to introduce a non-etcd backend cleanly. This change extracts a backend-neutral snapshot store interface, keeps the existing serializer-backed path as one implementation, and adds a Redis snapshot catalog backend as another implementation.

Module

  • Transfer Engine (mooncake-transfer-engine)
  • Mooncake Store (mooncake-store)
  • Mooncake EP (mooncake-ep)
  • Integration (mooncake-integration)
  • P2P Store (mooncake-p2p-store)
  • Python Wheel (mooncake-wheel)
  • PyTorch Backend (mooncake-pg)
  • Mooncake RL (mooncake-rl)
  • CI/CD
  • Docs
  • Other

Type of Change

  • Bug fix
  • New feature
  • Refactor
  • Breaking change
  • Documentation update
  • Other

What changes

  • abstract snapshot catalog operations behind a dedicated snapshot store interface in MasterService
  • add SerializerSnapshotStore to represent the existing snapshot catalog path explicitly
  • add RedisSnapshotStore with support for:
    • Publish
    • GetLatest
    • List
    • Delete
  • tighten GetLatest() semantics so callers can distinguish:
    • snapshot not found
    • backend read / decode error
  • extract shared Redis connection helpers so Redis HA and Redis snapshot catalog use the same endpoint / auth / DB-selection behavior
  • unify Redis test helpers used by HA and snapshot tests

Non-goals

This PR does not try to solve the full hot-standby recovery story yet.

In particular, it does not introduce:

  • snapshot recovery boundary semantics
  • last_included_seq / producer_view_version population
  • snapshot + oplog replay integration
  • follower-side snapshot catch-up workflow

Those should be handled in follow-up changes together with the broader replication / recovery design.

How Has This Been Tested?

Built with Redis + etcd enabled:

  • cmake --build build --target redis_snapshot_store_test high_availability_test -j8

Passed:

  • ./redis_snapshot_store_test --redis_endpoint=<redis-endpoint>
  • ./high_availability_test --redis_endpoint=<redis-endpoint>

On the validated setup:

  • redis_snapshot_store_test: 3/3 passed
  • high_availability_test: 9/9 passed

Checklist

  • I have performed a self-review of my own code.
  • I have formatted my own code using ./scripts/code_format.sh before submitting.
  • I have updated the documentation.
  • I have added tests to prove my changes are effective.

Xingrui Yi added 5 commits March 25, 2026 10:54
Introduce SerializerSnapshotStore as the snapshot catalog adapter for the existing serializer backend and route MasterService persist, restore, and cleanup flows through it instead of open-coding latest marker updates and snapshot directory scans.

Also add focused unit coverage for publish/get/list/delete behavior so the snapshot catalog path can evolve independently from the payload storage path.

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>
Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>
Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>
Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>
Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>
@YiXR
YiXR requested review from XucSh, stmatengss and ykwd as code owners March 25, 2026 03:16
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the snapshot management system within mooncake-store by introducing a clear abstraction layer for snapshot catalog operations. This change decouples the snapshot catalog logic from the MasterService, making it more modular and extensible. It enables the integration of alternative storage solutions for snapshot metadata, with a new Redis-backed implementation provided as a primary example. The refactoring also includes improvements to error handling and consolidates Redis connection utilities, enhancing the overall robustness and maintainability of the system.

Highlights

  • Snapshot Catalog Abstraction: Abstracted snapshot catalog handling in mooncake-store behind a new SnapshotStore interface, allowing for cleaner integration of different backends.
  • Redis Snapshot Backend: Introduced a new RedisSnapshotStore implementation, providing Redis-backed storage for snapshot metadata, including Publish, GetLatest, List, and Delete operations.
  • Explicit Serializer Backend: Created SerializerSnapshotStore to explicitly represent the existing serializer-backed snapshot catalog behavior, adhering to the new SnapshotStore interface.
  • Unified Redis Connection Helpers: Extracted and unified shared Redis connection helper functions, ensuring consistent endpoint parsing, authentication, and DB selection across Redis HA and snapshot catalog implementations.
  • Improved Snapshot Semantics: Tightened GetLatest() semantics to clearly distinguish between a snapshot not being found and backend read/decode errors.
  • Configuration Updates: Added new configuration options (snapshot_catalog_backend_type, snapshot_catalog_backend_connstring) to MasterConfig and related classes to support the new pluggable snapshot catalog backends.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new Redis-backed snapshot catalog for the mooncake-store master service, providing an alternative to the existing serializer-backed catalog. Key changes include new Redis client helper and snapshot store implementations, updated MasterConfig with options for catalog type and connection string, and refactoring MasterService to use a generic SnapshotStore interface for snapshot management. The PersistState, CleanupOldSnapshot, and RestoreState methods have been updated to leverage this new abstraction. Review feedback suggests improving the efficiency and reducing duplication of the TrimAsciiWhitespace utility function and simplifying the MasterService::GetSnapshotStore() method by removing redundant lazy initialization logic.

Comment on lines +49 to +59
std::string TrimAsciiWhitespace(std::string value) {
while (!value.empty() &&
std::isspace(static_cast<unsigned char>(value.front()))) {
value.erase(value.begin());
}
while (!value.empty() &&
std::isspace(static_cast<unsigned char>(value.back()))) {
value.pop_back();
}
return value;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This TrimAsciiWhitespace function is inefficient because value.erase(value.begin()) has linear time complexity and is being called inside a loop. This can be optimized to have linear complexity overall by finding the first and last non-whitespace characters and creating a substring.

Additionally, this function is duplicated in mooncake-store/src/ha/serializer_snapshot_store.cpp. It would be best to move this to a shared utility file to avoid code duplication.

Here's a more efficient implementation. Since the function name is TrimAsciiWhitespace, using an explicit list of ASCII whitespace characters is more correct than the locale-dependent isspace().

std::string TrimAsciiWhitespace(std::string value) {
    const auto first = value.find_first_not_of(" \t\n\r\f\v");
    if (std::string::npos == first) {
        return "";
    }
    const auto last = value.find_last_not_of(" \t\n\r\f\v");
    return value.substr(first, (last - first + 1));
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved the shared snapshot parsing/building helpers into a common snapshot helper so both serializer- and Redis-backed snapshot stores now use the same implementation. I also switched the trim logic to a linear first/last non-whitespace scan.

Comment on lines +2882 to +2887
ha::SnapshotStore* MasterService::GetSnapshotStore() {
if (!snapshot_store_ && snapshot_backend_) {
snapshot_store_ = CreateSnapshotStore();
}
return snapshot_store_.get();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The lazy initialization logic here seems redundant and could be confusing. The MasterService constructor already initializes snapshot_store_ via CreateSnapshotStore() right after snapshot_backend_ is created (inside the if (enable_snapshot_ || enable_snapshot_restore_) block).

Therefore, the condition !snapshot_store_ && snapshot_backend_ should never be true, making the lazy initialization appear to be dead code.

To improve clarity and remove the redundancy, you could simplify this method to just return snapshot_store_.get(). If there's a scenario where this lazy initialization is needed that I'm missing, it would be helpful to add a comment explaining it.

ha::SnapshotStore* MasterService::GetSnapshotStore() {
    return snapshot_store_.get();
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kept the eager constructor path for the normal case, but changed GetSnapshotStore() so the fallback path is synchronized and only materializes the store when snapshot_backend_ is injected after construction. That preserves the late-bound test path without leaving an unsynchronized lazy-init branch.

@codecov-commenter

codecov-commenter commented Mar 25, 2026

Copy link
Copy Markdown

@stmatengss
stmatengss requested a review from Copilot March 25, 2026 09:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors snapshot catalog handling in mooncake-store behind a backend-neutral SnapshotStore interface and introduces a Redis-backed snapshot catalog implementation alongside the existing serializer-backed behavior.

Changes:

  • Added SerializerSnapshotStore abstraction for the existing snapshot catalog marker behavior and updated MasterService to use a SnapshotStore.
  • Implemented RedisSnapshotStore (Publish/GetLatest/List/Delete) with shared Redis connection helpers and updated HA Redis coordinator to reuse them.
  • Added/updated Redis and snapshot-store tests and wired new test targets into CMake.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
mooncake-store/tests/serializer_snapshot_store_test.cpp New unit tests for serializer-backed snapshot catalog semantics.
mooncake-store/tests/redis_test_utils.h Shared Redis test helpers for HA + snapshot store tests.
mooncake-store/tests/redis_snapshot_store_test.cpp New Redis snapshot catalog integration tests.
mooncake-store/tests/high_availability_redis_test.cpp Switched HA Redis tests to use shared Redis helpers.
mooncake-store/tests/CMakeLists.txt Added new test target(s) for snapshot store tests.
mooncake-store/src/serialize/serializer_backend.cpp Added “not found” error classification for S3/local backends.
mooncake-store/src/master_service.cpp Routes snapshot catalog operations through SnapshotStore + adds backend selection.
mooncake-store/src/master.cpp Added CLI/config flags for snapshot catalog backend selection and connstring override.
mooncake-store/src/ha/serializer_snapshot_store.cpp New serializer-backed snapshot store implementation.
mooncake-store/src/ha/redis_snapshot_store.cpp New Redis-backed snapshot store implementation using Redis scripts.
mooncake-store/src/ha/redis_leader_coordinator.cpp Reused shared Redis connect helpers to reduce duplicated parsing/auth/DB selection logic.
mooncake-store/src/ha/redis_client_helper.cpp New shared Redis connect + parsing + key-tag utilities.
mooncake-store/src/CMakeLists.txt Added newly introduced HA source files to build.
mooncake-store/include/serialize/serializer_backend.h Added IsNotFoundError() hook to classify missing objects.
mooncake-store/include/master_service.h Added SnapshotStore members/factory accessors in MasterService.
mooncake-store/include/master_config.h Added snapshot catalog backend config fields and builder wiring.
mooncake-store/include/ha/serializer_snapshot_store.h Declared SerializerSnapshotStore.
mooncake-store/include/ha/backends/redis/redis_snapshot_store.h Declared RedisSnapshotStore.
mooncake-store/include/ha/backends/redis/redis_client_helper.h Declared shared Redis helper APIs/types.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 133 to 138
auto redis = ConnectRedisForTest(FLAGS_redis_endpoint);
ASSERT_NE(redis, nullptr);
ASSERT_TRUE(redis.has_value());
const auto master_view_key = BuildRedisMasterViewKey(cluster_namespace);
RedisReplyPtr delete_reply(static_cast<redisReply*>(
redisCommand(redis.get(), "DEL %b", master_view_key.data(),
redisCommand(redis->get(), "DEL %b", master_view_key.data(),
master_view_key.size())));

Copilot AI Mar 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConnectRedisForTest and BuildRedisMasterViewKey were moved into mooncake::testing in redis_test_utils.h, but this call site still uses unqualified names inside namespace mooncake. This will fail to compile unless there’s a local using declaration not shown in the diff. Prefer qualifying the calls (e.g., testing::ConnectRedisForTest, testing::BuildRedisMasterViewKey) or adding explicit using mooncake::testing::...; in the local anonymous namespace.

Copilot uses AI. Check for mistakes.
Comment thread mooncake-store/tests/CMakeLists.txt Outdated
${MOONCAKE_STORE_HIREDIS_INCLUDE_DIR})
target_link_libraries(redis_snapshot_store_test
PUBLIC mooncake_store transfer_engine cachelib_memory_allocator
${ETCD_WRAPPER_LIB} glog gflags ibverbs gtest gtest_main pthread

Copilot AI Mar 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redis_snapshot_store_test.cpp defines its own main(), but the target links gtest_main, which also provides main(). This typically causes a duplicate symbol linker error. Fix by removing gtest_main from target_link_libraries(...) for this target, or removing the custom main() from the test source and letting gtest_main handle it (if you still need gflags parsing, keep the custom main() and drop gtest_main).

Suggested change
${ETCD_WRAPPER_LIB} glog gflags ibverbs gtest gtest_main pthread
${ETCD_WRAPPER_LIB} glog gflags ibverbs gtest pthread

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest update: I dropped gtest_main from the redis_snapshot_store_test target since the test already provides its own main().

Comment thread mooncake-store/src/master_service.cpp Outdated

ha::SnapshotStore* MasterService::GetSnapshotStore() {
if (!snapshot_store_ && snapshot_backend_) {
snapshot_store_ = CreateSnapshotStore();

Copilot AI Mar 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetSnapshotStore() lazily initializes snapshot_store_ without synchronization, which can race if multiple threads call it concurrently (writes to a std::unique_ptr are not thread-safe). A concrete fix is to guard initialization with a mutex/shared_mutex (you already have snapshot_mutex_, if appropriate), or use std::once_flag + std::call_once. Alternatively, since the constructor already sets snapshot_store_ = CreateSnapshotStore();, consider removing the lazy-init path entirely to avoid split initialization logic.

Suggested change
snapshot_store_ = CreateSnapshotStore();
std::unique_lock<std::shared_mutex> lock(snapshot_mutex_);
if (!snapshot_store_ && snapshot_backend_) {
snapshot_store_ = CreateSnapshotStore();
}

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated GetSnapshotStore() so the fallback materialization path is synchronized. The normal path is still eager construction, and the lazy path now only exists for the late-bound backend case used by tests.

Comment on lines +287 to +302
RedisReplyPtr reply(static_cast<redisReply*>(redisCommand(
context->get(), "EVAL %s 2 %b %b %b", kDeleteSnapshotScript,
index_key_.data(), index_key_.size(), latest_key_.data(),
latest_key_.size(), snapshot_id.data(), snapshot_id.size())));
if (reply == nullptr || reply->type == REDIS_REPLY_ERROR) {
return ErrorCode::PERSISTENT_FAIL;
}

auto delete_result = payload_backend_->DeleteObjectsWithPrefix(
BuildSnapshotPrefix(snapshot_id));
if (!delete_result) {
LOG(ERROR) << "Failed to delete snapshot payload after Redis catalog "
"update, snapshot_id="
<< snapshot_id << ", error=" << delete_result.error();
return ErrorCode::PERSISTENT_FAIL;
}

Copilot AI Mar 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete() updates the Redis catalog first and deletes payload objects second; if payload deletion fails, the catalog no longer references the payload, leaving orphaned snapshot data and making automated cleanup harder. Consider reordering (delete payload first, then update Redis) or implementing a compensating action on failure (e.g., re-add the snapshot to the ZSET and re-set latest if needed), acknowledging the tradeoff that cross-backend atomicity isn’t possible but inconsistency can be minimized.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If payload deletion fails afterwards, we may leave orphaned payload, but reversing the order risks leaving the catalog/latest marker pointing to missing payload, which is the worse user-visible inconsistency. A follow-up GC/compensation path would be a better improvement here.

return snapshots;
}

ErrorCode SerializerSnapshotStore::Delete(const SnapshotId& snapshot_id) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need check if the snapshot_id is latest

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SerializerSnapshotStore::Delete() now checks whether the removed snapshot is the current latest marker, advances it to the next snapshot when available, and clears the latest marker when deleting the last snapshot.

Comment thread mooncake-store/src/master_service.cpp Outdated
}

ha::SnapshotStore* MasterService::GetSnapshotStore() {
if (!snapshot_store_ && snapshot_backend_) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check of snapshot_backend_ here is strange. may put it somewhere else

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tightened this path in the latest update. The normal case still uses constructor-time initialization, and GetSnapshotStore() now only falls back to synchronized late materialization when snapshot_backend_ is injected after construction. That lets us remove the old split/unsynchronized behavior while keeping the late-bound test path working.

Comment thread mooncake-store/src/master_service.cpp Outdated

ha::SnapshotStore* MasterService::GetSnapshotStore() {
if (!snapshot_store_ && snapshot_backend_) {
snapshot_store_ = CreateSnapshotStore();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now CreateSnapshotStore is called in MasterService, why check it here


#else

tl::expected<RedisContextPtr, ErrorCode> ConnectRedis(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This func is called in every api, should we make it a long connect?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Snapshot catalog operations are not on a hot path today, and keeping per-call connections avoids introducing shared hiredis context / reconnect / threading complexity prematurely. If catalog operations become measurable in practice, connection reuse would be a reasonable follow-up.


bool IsDigit(char ch) { return std::isdigit(static_cast<unsigned char>(ch)); }

bool IsValidSnapshotId(std::string_view snapshot_id) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make it a common function

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The duplicated snapshot helper logic is now shared instead of being implemented independently in both snapshot store backends.

Comment thread mooncake-store/src/master_service.cpp Outdated
if (std::regex_search(object_key, match, state_dir_regex)) {
snapshot_dirs.insert(match[1].str()); // Extract timestamp part
}
auto list_result = snapshot_store->List(0);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make the 0 a macro

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced the List(0) callsite with a named unlimited-list constant for readability.

@@ -117,6 +117,15 @@ class SerializerBackend {
virtual tl::expected<void, std::string> ListObjectsWithPrefix(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why there are two localtions for the serialize related api

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The split is intentional here: SerializerBackend is the payload/object-store primitive layer, while SnapshotStore is the snapshot catalog semantics layer. This PR only abstracts the catalog side, so I’d prefer to keep that layering explicit instead of collapsing the two concerns in the same change.

// or restore is enabled
// Snapshot payload storage backend type: "local" or "s3", required when
// snapshot or restore is enabled
std::string snapshot_backend_type;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is only used for serial? maybe make it more abstract

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this PR I kept snapshot_backend_type as the payload-backend knob and snapshot_catalog_backend_type as the catalog-backend knob. That seemed like the smallest change that makes the split explicit without expanding the scope into a config rename/migration.

@@ -0,0 +1,223 @@
#include "ha/backends/redis/redis_client_helper.h"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both leader election and snapshot management can be offloaded to Redis. maybe isolate the snapshot directory from the leader election mechanism to decouple these two distinct responsibilities.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The shared Redis helper here is only the low-level transport/auth/endpoint utility. The actual semantics remain separated in the leader-coordinator and snapshot-store implementations. I kept the helper shared in this PR to avoid duplicating the same connection logic in two places.

Comment thread mooncake-store/src/master_service.cpp Outdated
const std::string& snapshot_id) {
try {
auto* snapshot_store = GetSnapshotStore();
if (!snapshot_backend_ || !snapshot_store) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same above. this check looks unnecessary.

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>
@YiXR
YiXR force-pushed the xinyi/ha-snapshot branch from a5f4e86 to 26aded8 Compare March 26, 2026 07:27
@XucSh
XucSh merged commit 50bc7cf into kvcache-ai:main Mar 27, 2026
17 of 18 checks passed
Bo-Vincent pushed a commit to openanolis/Mooncake that referenced this pull request Mar 30, 2026
…ache-ai#1739)

* [STORE] abstract snapshot catalog in master service

Introduce SerializerSnapshotStore as the snapshot catalog adapter for the existing serializer backend and route MasterService persist, restore, and cleanup flows through it instead of open-coding latest marker updates and snapshot directory scans.

Also add focused unit coverage for publish/get/list/delete behavior so the snapshot catalog path can evolve independently from the payload storage path.

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>

* [STORE] distinguish missing snapshots from backend read errors

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>

* [STORE] add Redis snapshot catalog backend

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>

* [STORE] share Redis connection helpers across HA backends

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>
Co-authored-by: Xuchun Shang <xuchun.shang@linux.alibaba.com>

* [STORE] unify Redis test helpers

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>

* [STORE] tighten snapshot catalog state handling

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>

---------

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>
whn09 pushed a commit to whn09/Mooncake that referenced this pull request Apr 4, 2026
…ache-ai#1739)

* [STORE] abstract snapshot catalog in master service

Introduce SerializerSnapshotStore as the snapshot catalog adapter for the existing serializer backend and route MasterService persist, restore, and cleanup flows through it instead of open-coding latest marker updates and snapshot directory scans.

Also add focused unit coverage for publish/get/list/delete behavior so the snapshot catalog path can evolve independently from the payload storage path.

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>

* [STORE] distinguish missing snapshots from backend read errors

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>

* [STORE] add Redis snapshot catalog backend

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>

* [STORE] share Redis connection helpers across HA backends

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>
Co-authored-by: Xuchun Shang <xuchun.shang@linux.alibaba.com>

* [STORE] unify Redis test helpers

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>

* [STORE] tighten snapshot catalog state handling

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>

---------

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>
A-Liuhao pushed a commit to A-Liuhao/Mooncake that referenced this pull request Jun 25, 2026
…ache-ai#1739)

* [STORE] abstract snapshot catalog in master service

Introduce SerializerSnapshotStore as the snapshot catalog adapter for the existing serializer backend and route MasterService persist, restore, and cleanup flows through it instead of open-coding latest marker updates and snapshot directory scans.

Also add focused unit coverage for publish/get/list/delete behavior so the snapshot catalog path can evolve independently from the payload storage path.

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>

* [STORE] distinguish missing snapshots from backend read errors

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>

* [STORE] add Redis snapshot catalog backend

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>

* [STORE] share Redis connection helpers across HA backends

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>
Co-authored-by: Xuchun Shang <xuchun.shang@linux.alibaba.com>

* [STORE] unify Redis test helpers

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>

* [STORE] tighten snapshot catalog state handling

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>

---------

Signed-off-by: Xingrui Yi <yixingrui@linux.alibaba.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants